package cart.service.impl;

import cart.service.CartService;
import cart.vo.CartInfo;
import cart.vo.CartTemp;
import cart.vo.SkuInfoVo;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import lombok.extern.slf4j.Slf4j;
import com.feign.constant.AuthServerConstant;
import com.feign.constant.CartConstant;
import com.feign.product.SkuInfoFeignService;
import com.feign.product.SkuSaleAttrValueFeignService;
import com.feign.utils.R;
import com.feign.vo.LoginResVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class CartServiceImpl implements CartService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private SkuInfoFeignService skuInfoFeignService;

    @Autowired
    private SkuSaleAttrValueFeignService skuSaleAttrValueFeignService;


    @Override
    public CartInfo addToCart(Long skuId, Integer skuNum, HttpServletRequest request) {
        BoundHashOperations<String, Object, Object> cartKeyOps = getCartKey(request);
        // 判断是否是商品新增操作
        String res = (String) cartKeyOps.get(skuId.toString());
        if (ObjectUtils.isEmpty(res)) {
            // 商品新增操作
            // 远程调用商品服务，查询商品详情
            R r = skuInfoFeignService.info(skuId);
            SkuInfoVo skuInfoVo = r.getData("data", new TypeReference<SkuInfoVo>() {
            });
            // 添加到购物车
            CartInfo cartItem = new CartInfo();
            cartItem.setIsChecked(1);
            cartItem.setSkuNum(skuNum);
            cartItem.setImgUrl(skuInfoVo.getSkuDefaultImg());
            cartItem.setSkuName(skuInfoVo.getSkuTitle());
            cartItem.setSkuId(skuId);
            cartItem.setSkuPrice(skuInfoVo.getPrice());
            cartItem.setCartPrice(skuInfoVo.getPrice().multiply(BigDecimal.valueOf(skuNum)));
            // 远程查询sku信息的组合
            //List<String> saleAttrValues = skuSaleAttrValueFeignService.getSkuSaleAttrValues(skuId);
            //cartItem.setSkuAttr(saleAttrValues);
            // 转json字符串给redis存
            String jsonString = JSON.toJSONString(cartItem);
            cartKeyOps.put(skuId.toString(), jsonString);
            return cartItem;
        } else {
            CartInfo cartItem = JSONUtil.toBean(res, CartInfo.class);
            // 更新商品的数量
            cartItem.setSkuNum(cartItem.getSkuNum() + skuNum);
            // 更新购物项总价
            cartItem.setCartPrice(cartItem.getSkuPrice().multiply(BigDecimal.valueOf(cartItem.getSkuNum())));
            cartKeyOps.put(skuId.toString(), JSON.toJSONString(cartItem));
            return cartItem;
        }
    }

    @Override
    public CartTemp getCart(HttpServletRequest request) {
        // 判断用户是否登录，来生成区别购物车的key
        BoundHashOperations<String, Object, Object> cartKeyOps = getCartKey(request);
        List<Object> cartInfoObj = cartKeyOps.values();
        CartTemp cartTemp = new CartTemp();
        List<CartInfo> cartInfoList;
        if (!ObjectUtils.isEmpty(cartInfoObj)) {
            cartInfoList = cartInfoObj.stream().map(item -> {
                String skuInfoStr = (String) item;
                // 转成对象
                return JSONUtil.toBean(skuInfoStr, CartInfo.class);
            }).collect(Collectors.toList());
            cartTemp.setCartInfoList(cartInfoList);
        }
        // 合并购物车
        // 判断用户是否登录
        String token = request.getHeader("token");
        if (!ObjectUtils.isEmpty(token)) {
            String user = redisTemplate.opsForValue().get(AuthServerConstant.TOKEN + token);
            LoginResVo loginResVo = JSONUtil.toBean(user, LoginResVo.class);
            // 身份验证通过
            String cartKey = CartConstant.CART_PREFIX + loginResVo.getUserId().toString();
            // 判断临时购物车是否有数据
            String userTempId = request.getHeader("userTempId");
            String cartTempKey = CartConstant.CART_PREFIX + userTempId;
            //List<Object> tempCartData = redisTemplate.opsForHash().values(cartKey);
            List<CartInfo> cartTempItems = getCartItems(cartTempKey);
            if (!ObjectUtils.isEmpty(cartTempItems)) {
                // 临时购物车有数据，进行合并到当前登录用户的购物车
                cartTempItems.forEach(item -> addToCart(item.getSkuId(), item.getSkuNum(), request));
                List<CartInfo> cartItems = getCartItems(cartKey);
                // 删除临时购物车的key
                redisTemplate.delete(cartTempKey);
                cartTemp.setCartInfoList(cartItems);
                return cartTemp;
            }
        }
        return cartTemp;
    }

    @Override
    public void deleteCartInfo(Long skuId, HttpServletRequest request) {
        BoundHashOperations<String, Object, Object> cartKeyOps = getCartKey(request);
        cartKeyOps.delete(skuId.toString());
    }

    @Override
    public void checked(Long skuId, Integer isChecked, HttpServletRequest request) {
        // 查询购物车里面的商品
        CartInfo cartItem = getCartItem(skuId, request);
        // 修改商品状态
        cartItem.setIsChecked(isChecked);
        // 序列化存入redis中
        String redisValue = JSON.toJSONString(cartItem);
        BoundHashOperations<String, Object, Object> cartOps = getCartKey(request);
        cartOps.put(skuId.toString(), redisValue);
    }

    @Override
    public CartInfo getCartItem(Long skuId, HttpServletRequest request) {
        // 拿到要操作的购物车商品项信息
        BoundHashOperations<String, Object, Object> cartOps = getCartKey(request);
        String redisValue = (String) cartOps.get(skuId.toString());
        return JSON.parseObject(redisValue, CartInfo.class);
    }

    @Override
    public List<CartInfo> getCheckedCart(String token) {
        BoundHashOperations<String, Object, Object> cartKeyOps = getCartKeyByToken(token);
        List<Object> values = cartKeyOps.values();
        if (!ObjectUtils.isEmpty(values)) {
            return values.stream().map((obj) -> {
                String str = (String) obj;
                return JSON.parseObject(str, CartInfo.class);
            }).filter(item -> item.getIsChecked() == 1).collect(Collectors.toList());
        }
        return null;
    }

    private BoundHashOperations<String, Object, Object> getCartKeyByToken(String token) {
        // 判断用户是否登录
        String cartKey = null;
        if (!ObjectUtils.isEmpty(token)) {
            String user = redisTemplate.opsForValue().get(AuthServerConstant.TOKEN + token);
            if (!ObjectUtils.isEmpty(user)) {
                LoginResVo loginResVo = JSONUtil.toBean(user, LoginResVo.class);
                // 身份验证通过
                cartKey = CartConstant.CART_PREFIX + loginResVo.getUserId().toString();
            }
        }
        assert cartKey != null;
        return redisTemplate.boundHashOps(cartKey);
    }

    /**
     * 获取需要操作购物车中的keyOps
     */
    private BoundHashOperations<String, Object, Object> getCartKey(HttpServletRequest request) {
        // 判断用户是否登录
        String cartKey;
        String token = request.getHeader("token");
        String userTempId = request.getHeader("userTempId");
        if (!ObjectUtils.isEmpty(token)) {
            String user = redisTemplate.opsForValue().get(AuthServerConstant.TOKEN + token);
            if (!ObjectUtils.isEmpty(user)) {
                LoginResVo loginResVo = JSONUtil.toBean(user, LoginResVo.class);
                // 身份验证通过
                cartKey = CartConstant.CART_PREFIX + loginResVo.getUserId().toString();
            } else {
                cartKey = CartConstant.CART_PREFIX + userTempId;
            }
        } else {
            cartKey = CartConstant.CART_PREFIX + userTempId;
        }
        return redisTemplate.boundHashOps(cartKey);
    }

    private List<CartInfo> getCartItems(String cartKey) {
        //获取购物车里面的所有商品
        BoundHashOperations<String, Object, Object> operations = redisTemplate.boundHashOps(cartKey);
        List<Object> values = operations.values();
        if (values != null && values.size() > 0) {
            return values.stream().map((obj) -> {
                String str = (String) obj;
                return JSON.parseObject(str, CartInfo.class);
            }).collect(Collectors.toList());
        }
        return null;
    }


}
